import streamlit as st
import pandas as pd
import plotly.express as px
import plotly.graph_objects as go
from datetime import datetime
import numpy as np
import os

from value_stocks import ValueStockAnalyzer
from data_cache import DataCache
import config

# 页面配置
st.set_page_config(
    page_title="格雷厄姆价值投资分析器",
    page_icon="📈",
    layout="wide"
)

# 初始化价值股分析器
@st.cache_resource
def get_value_analyzer():
    return ValueStockAnalyzer()

def main():
    # 页面标题
    st.title("格雷厄姆价值投资分析器")
    st.markdown("基于格雷厄姆价值投资理念，筛选A股市场中被低估且有低吸机会的股票")
    
    # 初始化缓存管理器
    cache = DataCache()
    
    # 显示缓存状态
    cache_dir = "./cache"
    if os.path.exists(cache_dir):
        cache_files = [f for f in os.listdir(cache_dir) if f.endswith('.pkl')]
        if cache_files:
            with st.expander("缓存状态"):
                st.info(f"当前缓存文件数量: {len(cache_files)}")
                if st.button("清除所有缓存"):
                    cache.clear_cache()
                    st.success("缓存已清除！")
                    st.experimental_rerun()
    
    # 侧边栏配置
    st.sidebar.header("参数设置")
    
    # 成交额排名
    top_volume = st.sidebar.slider(
        "成交额前N名", 
        min_value=50, 
        max_value=500, 
        value=200,
        step=50
    )
    
    # 价值股筛选参数
    st.sidebar.subheader("价值股筛选标准")
    
    pe_threshold = st.sidebar.slider(
        "市盈率(PE)上限", 
        min_value=5, 
        max_value=30, 
        value=15,
        step=1
    )
    
    pb_threshold = st.sidebar.slider(
        "市净率(PB)上限", 
        min_value=0.5, 
        max_value=3.0, 
        value=1.5,
        step=0.1
    )
    
    div_yield_threshold = st.sidebar.slider(
        "股息率(%)下限", 
        min_value=1.0, 
        max_value=10.0, 
        value=4.0,
        step=0.5
    )
    
    market_cap_threshold = st.sidebar.slider(
        "市值下限(亿元)", 
        min_value=10, 
        max_value=500, 
        value=100,
        step=10
    )
    
    # 低吸参数
    st.sidebar.subheader("低吸策略参数")
    
    drop_min = st.sidebar.slider(
        "最小跌幅(%)", 
        min_value=1.0, 
        max_value=5.0, 
        value=2.0,
        step=0.5
    )
    
    drop_max = st.sidebar.slider(
        "最大跌幅(%)", 
        min_value=3.0, 
        max_value=10.0, 
        value=6.0,
        step=0.5
    )
    
    # 添加缓存控制
    use_cache = st.sidebar.checkbox("使用缓存数据", value=True, help="如果取消选中，将从网络重新获取所有数据")
    
    # 获取数据按钮
    if st.sidebar.button("分析价值股"):
        with st.spinner("正在获取和分析股票数据..."):
            try:
                # 如果不使用缓存，先清除缓存
                if not use_cache:
                    cache.clear_cache()
                    st.info("缓存已清除，将从网络重新获取数据")
                
                # 创建进度条
                progress_bar = st.progress(0)
                status_text = st.empty()
                
                # 更新状态
                status_text.text("正在初始化分析器...")
                progress_bar.progress(10)
                
                value_analyzer = get_value_analyzer()
                
                # 更新状态
                status_text.text("正在获取股票数据...")
                progress_bar.progress(30)
                
                # 添加日志显示区域
                log_container = st.empty()
                
                # 重定向打印输出到Streamlit
                import sys
                from io import StringIO
                
                old_stdout = sys.stdout
                sys.stdout = mystdout = StringIO()
                
                data, error = value_analyzer.get_low_suction_stocks(
                    drop_min=drop_min,
                    drop_max=drop_max,
                    top_volume=top_volume,
                    pe_threshold=pe_threshold,
                    pb_threshold=pb_threshold,
                    div_yield_threshold=div_yield_threshold,
                    market_cap_threshold=market_cap_threshold
                )
                
                # 恢复标准输出
                sys.stdout = old_stdout
                
                # 显示日志
                with log_container.container():
                    st.text(mystdout.getvalue())
                
                # 更新状态
                status_text.text("分析完成!")
                progress_bar.progress(100)
                
                if error:
                    st.error(f"获取数据失败: {error}")
                elif data.empty:
                    st.warning("没有找到符合条件的价值股")
                else:
                    # 显示结果
                    st.subheader(f"成交额前{top_volume}名中符合格雷厄姆标准且跌幅在{drop_min}%-{drop_max}%的价值股")
                    
                    # 显示数据表格
                    st.dataframe(data[['代码', '名称', '最新价', '涨跌幅', '成交额', '总市值']], use_container_width=True)
                    
                    # 创建可视化图表
                    create_visualizations(data)
                    
                    # 显示投资建议
                    show_investment_advice(data, drop_max)
            except Exception as e:
                st.error(f"分析过程中出错: {str(e)}")
    else:
        # 首次加载页面时显示的内容
        st.info("👈 请在左侧设置参数并点击'分析价值股'按钮开始分析")
        st.markdown("""
        ### 格雷厄姆价值投资理念
        
        本应用基于本杰明·格雷厄姆的价值投资理念，结合A股市场特点，筛选被低估且有低吸机会的股票。
        
        #### 核心筛选标准
        
        - **市盈率(PE)低：** 低于行业平均或历史均值（格雷厄姆喜欢PE<15）
        - **市净率(PB)低：** PB<1.5，最好<1，代表股价低于每股净资产
        - **股息率高：** >3%-4%，证明公司赚钱还分红
        - **市值要求：** 大公司（市值>100亿，A股蓝筹多），财务稳健
        
        #### 低吸策略
        
        从成交额前N名的股票中，筛选出符合格雷厄姆价值投资标准，且当日跌幅在2%-6%的股票，提供低吸机会。
        
        #### 投资建议
        
        - 分散投资：从筛选结果中选择5-10只股票进行投资
        - 安全边际：股价比内在价值低30%-50%，提供安全边际
        - 长期持有：价值投资强调长期持有，等待市场回归理性
        """)

def create_visualizations(data):
    """创建数据可视化图表"""
    st.subheader("数据可视化")
    
    try:
        # 创建两列布局
        col1, col2 = st.columns(2)
        
        with col1:
            # 跌幅排名条形图
            try:
                # 确保数据不为空
                if len(data) > 0:
                    fig_drop = px.bar(
                        data.sort_values('涨跌幅', ascending=True).head(10),
                        y='名称',
                        x='涨跌幅',
                        orientation='h',
                        title="跌幅排名",
                        labels={'涨跌幅': '跌幅(%)', '名称': '股票名称'},
                        color='涨跌幅',
                        color_continuous_scale='Reds'
                    )
                    fig_drop.update_layout(height=500)
                    st.plotly_chart(fig_drop, use_container_width=True)
                else:
                    st.info("没有足够的数据来创建跌幅排名图表")
            except Exception as e:
                st.warning(f"创建跌幅排名图表时出错: {str(e)}")
        
        with col2:
            # 市值分布饼图
            try:
                # 确保总市值列存在且有值
                if '总市值' in data.columns and not data['总市值'].isna().all():
                    # 创建市值区间
                    data['市值区间'] = pd.cut(
                        data['总市值'] / 100000000,  # 转换为亿元
                        bins=[0, 100, 300, 500, 1000, float('inf')],
                        labels=['<100亿', '100-300亿', '300-500亿', '500-1000亿', '>1000亿']
                    )
                    
                    market_cap_counts = data['市值区间'].value_counts().reset_index()
                    market_cap_counts.columns = ['市值区间', 'count']
                    
                    fig_market_cap = px.pie(
                        market_cap_counts,
                        values='count',
                        names='市值区间',
                        title="市值分布",
                        color_discrete_sequence=px.colors.qualitative.Set3
                    )
                    fig_market_cap.update_layout(height=500)
                    st.plotly_chart(fig_market_cap, use_container_width=True)
                else:
                    st.info("没有足够的数据来创建市值分布图表")
            except Exception as e:
                st.warning(f"创建市值分布图表时出错: {str(e)}")
    except Exception as e:
        st.error(f"创建可视化图表时出错: {str(e)}")

def show_investment_advice(data, drop_max):
    """显示投资建议"""
    st.subheader("投资建议")
    
    # 计算建议的投资组合
    if len(data) >= 5:
        # 按跌幅排序，选择跌幅最大的5只股票
        portfolio = data.sort_values('涨跌幅', ascending=True).head(5)
        
        st.markdown(f"""
        ### 建议投资组合
        
        基于格雷厄姆的价值投资理念和低吸策略，我们建议您考虑以下投资组合：
        
        1. **分散投资：** 从上述结果中选择跌幅接近{drop_max}%的5只股票
        2. **资金分配：** 假设总投资金额为50万元，每只股票分配10万元
        3. **买入策略：** 在当日收盘前买入，或等待次日继续回调时买入
        4. **持有策略：** 中长期持有，等待价值回归
        5. **止盈策略：** 当股价上涨10%-20%时考虑部分止盈
        """)
        
        # 显示建议投资组合
        st.markdown("#### 建议投资的5只股票")
        
        # 创建投资组合表格
        portfolio_table = portfolio[['代码', '名称', '最新价', '涨跌幅']].copy()
        portfolio_table['建议投资金额'] = "10万元"
        portfolio_table['预计可买入股数'] = (100000 / portfolio_table['最新价']).astype(int)
        
        st.dataframe(portfolio_table, use_container_width=True)
        
        # 显示投资注意事项
        st.markdown("""
        ### 投资注意事项
        
        1. **风险提示：** 股市有风险，投资需谨慎，本建议不构成投资建议
        2. **基本面分析：** 在投资前，请进一步研究公司的基本面、行业前景和财务状况
        3. **市场风险：** 即使是价值股，短期内也可能因市场情绪或宏观因素而下跌
        4. **长期视角：** 价值投资强调长期持有，不要因短期波动而恐慌卖出
        5. **定期复盘：** 每季度或半年检查一次投资组合，根据公司基本面变化调整
        """)
    else:
        st.info("没有足够的数据来提供投资建议，请调整筛选条件后重试")

if __name__ == "__main__":
    main()
